<?php
/**
 * vim: tabstop=4
 * 
 * @license		http://www.gnu.org/licenses/gpl.html GPL Version 3
 * @author		Ian Moore <imooreyahoo@gmail.com>
 * @copyright	Copyright (c) 2011 Ian Moore
 * @version		$Id: mysql.inc 69 2011-12-09 21:07:20Z imooreyahoo@gmail.com $
 *
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this file. If not, see <http://www.gnu.org/licenses/>.
 */
require_once("openmediavault/module.inc");
require_once("openmediavault/config.inc");
require_once("openmediavault/error.inc");
require_once("openmediavault/util.inc");
require_once("openmediavault/initscript.inc");
require_once(dirname(dirname(__FILE__)).'/rpc/mysql.inc');

class MySQLModule extends OMVModuleAbstract implements OMVINotifyListener, OMVIModuleStatus {
	
	/**
	 * Get the module name.
	 */
	public static function getName() {
		return "mysql";
	}

	/**
	 * Get the module status.
	 */
	public function getStatus() {
		
		global $xmlConfig;
		
		// Get the configuration object
		$xpath = "//services/mysql";
		$object = $xmlConfig->get($xpath);
		if (is_null($object)) {
			throw new OMVException(OMVErrorMsg::E_CONFIG_GET_OBJECT_FAILED, $xpath);
		}
		
        $initd = new OMVSysVInitScript("mysql");
        return array(
            "name" => $this->getName(),
            "title" => gettext("MySQL"),
            "enabled" => boolval($object['enable']),
            "running" => ($initd->status() == 0)
        );

	}

	/**
	 * Initialize MySQL
	 */
	private function setupService($conf, $econf) {
		
		$initd = new OMVSysVInitScript("mysql");
		
		// Stop MySQL if running
		try {
			$initd->stop();
		} catch (Exception $e) {
			// Ignored. Assume it's not running which is fine
		}
		
		// Ultimately files / folders must be readable / writable by mysql.
		$cmd = "sudo /bin/sh -c '[ -d {$conf['data-root']} ] || /bin/mkdir -p {$conf['data-root']}; chown mysql {$conf['data-root']}; chmod u+rwx {$conf['data-root']}'";
		OMVUtil::exec($cmd, $output, $result);
		if ($result !== 0) {
			throw new OMVException(OMVErrorMsg::E_EXEC_FAILED,	$cmd, implode("\n", $output));
		}
		
		// If mysql database already exists, this was previously
		// initialized and there's nothing more to do
		$cmd = "sudo /bin/sh -c 'if [ -d {$conf['data-root']}/mysql ]; then echo OK; else echo NO; fi'";
		OMVUtil::exec($cmd, $output, $result);
		if ($result !== 0) {
			throw new OMVException(OMVErrorMsg::E_EXEC_FAILED,	$cmd, implode("\n", $output));
		}
		if(trim($output[0]) == "OK") {
			// Start MySQL
			$initd->start();
			return;
		}
	
		// Initialize default tables
		$cmd = "sudo mysql_install_db";
		OMVUtil::exec($cmd, $output, $result);
		if ($result !== 0) {
			throw new OMVException(OMVErrorMsg::E_EXEC_FAILED,  $cmd, implode("\n", $output));
		}

		// Start MySQL
		$initd->start();

		// Assume blank root password
		// Access MySQL through existing functions in MySQLRpc
		$msql = new MySQLRpc();
		$msql->connect('');
		
		// Add debian user(s)
		exec("sudo php -r 'echo(serialize(parse_ini_file(\"/etc/mysql/debian.cnf\",true)));' 2>/dev/null", $out);
		foreach(unserialize($out[0]) as $s) {
			if(!$s['user']) continue;
			$users[$s['user']] = $s['password'];
		}
		foreach($users as $k=>$v) {
			$msql->query(sprintf("GRANT ALL PRIVILEGES ON *.* TO '%s'@'localhost' IDENTIFIED BY '%s';", $msql->escape($k), $msql->escape($v)));
		}
		
		/**
		 * This performs the same actions as /usr/bin/mysql_secure_installation
		 */
		
		// Remove empty users
		$msql->query("DELETE FROM mysql.user where USER = ''");
		
		// Drop test db
		$msql->query("DROP DATABASE IF EXISTS test");
		
		// Carry over root password from old data-root
		if(!empty($econf['password']) && !empty($conf['password']) && $econf['password'] == $conf['password']) {
			$msql->query(sprintf("UPDATE mysql.user SET Password=PASSWORD('%s') WHERE User='root';", $msql->escape($conf['password'])));
			$msql->query("FLUSH PRIVILEGES;");
		}
				
	}
	
	/**
	 * Update the service.
	 */
	public function updateService($conf, $oldconf) {

		// Create mysql config file
		$cmd = "sudo omv-mkconf mysql 2>&1";
		OMVUtil::exec($cmd, $output, $result);
		if ($result !== 0) {
			throw new OMVException(OMVErrorMsg::E_EXEC_FAILED, $cmd, implode("\n", $output));
		}
		
		
		// Create MySQL data root and initialize database
		if(!empty($conf['data-root']) && $oldconf['data-root'] != $conf['data-root']) {
			
			$this->setupService($conf, $oldconf);
					
		// Stop service
		} else if(!$conf['enable']) {

			$initd = new OMVSysVInitScript("mysql");
			$initd->stop();
			
		// Start service
		} else if(!$oldconf['enable']) {

			$initd = new OMVSysVInitScript("mysql");
			$initd->start();
			
		// restart service?
		} else {

			// If any of these values change, mysql should be restarted
			foreach(array('enable','data-root','enable-networking','port','bindaddress') as $k) {
		
				// So that these will match in a comparison
				if(empty($conf[$k])) $conf[$k] = '';
				if(empty($oldconf[$k])) $oldconf[$k] = '';

				if((string)$conf[$k] !== (string)$oldconf[$k]) {
					$initd = new OMVSysVInitScript("mysql");
					$initd->restart();
					break;
				}
			}
			
					
		}

		// Restart apache?
		$oldconf['enable-phpmyadmin'] = boolval($oldconf['enable-phpmyadmin']);
		if($conf['enable-phpmyadmin'] != $oldconf['enable-phpmyadmin']) {
			exec('sudo /etc/init.d/apache2 reload');
		}
		
	
	}

	/**
	 * 
	 * Bind notification listener
	 * @param OMVNotifyDispatcher $dispatcher
	 */
	function bindListeners(OMVNotifyDispatcher $dispatcher) {
		$dispatcher->addListener(OMV_NOTIFY_MODIFY,
			"org.openmediavault.services.mysql",
		array($this,"updateService"), 1);
	}

}

// Register module
$moduleMgr = &OMVModuleMgr::getInstance();
$moduleMgr->registerModule(new MySQLModule());

